#pragma once 
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include "Log.hpp"
#include <cstring>
using namespace MyLogModule;
const string sep = "\r\n";
const string linesep = ": ";
const string spacesep = " ";
const string default_http_version = "HTTP/1.0";
const string default_homedir = "wwwroot"; //穿过来的参数默认有/
const string default_homepath = "index.html"; //穿过来的参数默认有/
const string default_error_path = "wwwroot/404.html";

class Request
{
public:
    Request():_exec(false)
    {

    }
    //咱们这里解析只能是一个完整的报文, 因为此时我们并没有设置缓冲区
    //所以如果传过来的不是一个完整的报文我们会直接抛弃
    bool Deserialization(string& inbuffer){   
        if (!ParseHeadLine(inbuffer)) return false;
        //解析请求报头
        while(ParseOneLine(inbuffer)){ 
            if (!_bankline.empty()) break; //如果解析到了空行,就可以退出了
        }
        //如果没有解析到空行直接返回false
        if (_bankline.empty()) return false;
        if (_headkv.count("Content-Length")){
            int length = stoi(_headkv["Content-Length"]);
            _body = inbuffer.substr(0,length);
            inbuffer.erase(0,length);
        }
        return true;
    }   
    //服务端根本不需要对请求进行序列化
    // bool Serialization(string* out){

    // }   
    void Print(){
        LOG(LogLevel::INFO) << "#####################[请求报头]#####################";
        LOG(LogLevel::INFO) << "请求方法:[" << _method << "]-" <<"请求路径:[" << _url << "]-请求版本:[" << _version<<"]" ;
        for (auto& kv : _headkv){
            LOG(LogLevel::INFO) << kv.first << ": " << kv.second;
        }
        LOG(LogLevel::INFO) << _bankline;
        LOG(LogLevel::INFO) << _body;
        LOG(LogLevel::INFO) << "#####################[请求报头]#####################";
    }
    bool ParseHeadLine(string& s){ //解析请求行
        auto pos = s.find(sep); //我们自己找请求行
        if (pos == string::npos) return false;
        string line = s.substr(0,pos);
        stringstream ss(line);
        ss >> _method >> _url >> _version;
        if (_method.empty() || _url.empty() || _version.empty()) return false; //说明此时不是请求行
        s.erase(0,line.size() + sep.size());
        return true;
    }
    bool ParseOneLine(string& s){ //解析请求报头的其中一行
        auto pos = s.find(sep); //我们自己找请求行
        if (pos == string::npos) return false;
        string line = s.substr(0,pos);  
        if (line.empty()){
            _bankline = sep;
            s.erase(0,_bankline.size());
            return true;
        }      
        else {
            string k,v;
            auto pos = line.find(linesep);
            if (pos == string::npos) return false;
            k = line.substr(0,pos);
            v = line.substr(pos + linesep.size());
            if (!_headkv.count(k))
                _headkv[k] = v;
            else {
                LOG(LogLevel::ERROR) << "存在相同的请求报头";
                exit(1);
                return false;
            }
            s.erase(0,line.size()+sep.size());
            return true;
        }
    }
    //暂且就只需要管GET方法
    void CheckArgs(){
        auto pos = _url.find("?");
        if (pos == string::npos){
            _exec = false;
            return; //没有参数
        }
        // /login?username=125&passwd=242
        _path = _url.substr(0,pos);
        _args = _url.substr(pos+1);
        _exec = true;
    }
    string GetUrl() const {return _url;}
    string Path()const {return _path;} 
    string Args()const { return _args;}
    bool IsHasArg(){return _exec;}
    ~Request(){}    
private:
    string _method; //请求方法
    string _url; //请求路径
    string _version; //http版本
    string _path; //请求路径方法
    string _args; //请求的参数
    bool _exec;
    
    string _bankline; //空行
    string _body; //请求数据
    unordered_map<string,string> _headkv; //请求报头
};



class Response
{
public:
    Response()  :_version(default_http_version),_status(200)
    {

    }
    //服务端应答不需要反序列化
    // void Deserialization(const string& inbuffer){

    // }
    void Serialization(string* out){
        stringstream ss;
        _bankline = sep;
        ss << _version << spacesep << _status << spacesep<< _statusdec<< spacesep << sep;
        for (auto& kv : _headkv){
            ss << kv.first << linesep << kv.second << sep;
        }
        ss << _bankline;
        ss << _body;
        *out = ss.str();
    }
    void SetHeadKv(const string& k,const string& v){
        if (_headkv.count(v)){
            LOG(LogLevel::WARNING) << "重复的键:["<<k<<"]";
            return;
        }
        _headkv[k] = v;
    }
    string Status2Desc(int status){
        switch(status){
            case 200:
            return "OK";            
            case 404:
            return "Not Found";
            break;
            default:
            return "Bad Request";
        }
    }
    string BuildUrl(const string& url){
        /* 传过来的可能这些情况
        1. /
        2. /index.html, /login.html, /register.html, /image/1.jpg , 这里我们不考虑子目录的默认页面问题
        */
       string ret = default_homedir + url;
       if (ret.back() =='/') ret += default_homepath; //如果是/加上index/html
       return ret;
    }
    string GetContent(const string& path){
        ifstream ifs(path,std::ios::binary);
        if (!ifs.is_open()) {
            //文件不存在
            return "";
        }
        //设置此时的偏移量到文件的末尾
        ifs.seekg(0,ifs.end);
        int content_length = ifs.tellg(); //获取当前的偏移量
        if (content_length < 0) content_length = 0;
        ifs.seekg(0,ifs.beg); //设置到文件的起始位置
        string ret;
        ret.resize(content_length);
        ifs.read((char*)ret.c_str(),content_length);
        ifs.close();
        return ret;
    }
    string GetSuffix(const string& url){
        auto pos = url.rfind("."); //index.html
        if (pos == string::npos) return "";
        string suffix = url.substr(pos); //.html
        if (strcmp(suffix.c_str(),".html") == 0){
            return "text/html";
        }
        else if(strcmp(suffix.c_str(),".jpg") == 0){
            return "application/x-jpg";
        }
        else {
            return "text/html";
        }
    }
    void SetCode(int status){
        _status = status;
        _statusdec = Status2Desc(_status);
    }
    void SetSuffix(const string& path){
        SetHeadKv("Content-Type",GetSuffix(path));
    }
    void SetBody(const string& s){
        _body = s;
        SetHeadKv("Content-Length",to_string(_body.size()));
    }
    //通过请求应答构建响应
    void Build(const Request& req){
        //就是/.....
        string url = std::move(BuildUrl(req.GetUrl()));
        _body = GetContent(url);
        if (_body.empty()) {
            _status = 404;
            //这里得重新获取文件内容
            _body = GetContent(default_error_path);
        }
        _statusdec = Status2Desc(_status);
        //记得条件长度报头啊
        if (!_body.empty()){
            SetHeadKv("Content-Length",to_string(_body.size()));
        }
        string suffix;
        if (_status == 404){
            suffix = GetSuffix(default_error_path);
        }
        else {
            suffix = GetSuffix(url);
        }
        //添加文件后缀 //TODO
        if (!suffix.empty()){
            SetHeadKv("Content-Type",suffix);
        }
    }
    void Print(){
        LOG(LogLevel::INFO) << "#####################[响应报头]#####################";
        LOG(LogLevel::INFO) << "http版本:[" << _version << "]-" <<"响应状态码:[" << _status << "]-状态码描述:[" << _statusdec<<"]" ;
        for (auto& kv : _headkv){
            LOG(LogLevel::INFO) << kv.first << ": " << kv.second;
        }
        LOG(LogLevel::INFO) << _bankline;
        LOG(LogLevel::INFO) << "body size: " << _body.size();
        LOG(LogLevel::INFO) << "#####################[响应报头]#####################";
    }
    ~Response(){}    
private:
    string _version; //http版本
    int _status; //响应状态码
    string _statusdec; //状态码描述


    string _bankline; //空行
    string _body; //响应数据
    unordered_map<string,string> _headkv; //响应报头
};
